/* -*-c++-*- IfcGears - www.ifcgears.com  - Copyright (C) 2011 Fabian Gerold
 *
 * This library is open source and may be redistributed and/or modified under  
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 * OpenSceneGraph Public License for more details.
*/

#pragma once

#include <sstream>
#include <osgDB/ReaderWriter>

#include <osg/Group>
#include <osg/MatrixTransform>
#include <osgUtil/LineSegmentIntersector>

#include "ifcgears/model/shared_ptr.h"
#include "ifcgears/model/StatusObservable.h"

#ifdef __GNUC__
#include "ifcgears/model/IfcGearsModel.h"
#include "ifcgears/IFC2X4/include/AllIfcEntities.h"
#include "RepresentationConverter.h"
#else

class IfcGearsModel;
class IfcGearsReader;
class IfcStepWriter;
class UnitConverter;
class RepresentationConverter;
class IfcProject;
class IfcProduct;
class IfcSpace;
class IfcRelContainedInSpatialStructure;
class IfcRelAggregates;
class IfcBuildingStorey;
struct ItemData;
class productTreffer;
#endif


class ReaderWriterIFC : public osgDB::ReaderWriter, public StatusObservable
{
public:

	struct ModelGeomTree
	{
		ModelGeomTree()
		{
			storeys = new osg::MatrixTransform();
			products = new osg::Group();
			spaces = new osg::Group();
			terrain = new osg::Group();
		}
		void clear()
		{
			storeys->removeChildren(0,storeys->getNumChildren());
			products->removeChildren(0,products->getNumChildren());
			spaces->removeChildren(0,spaces->getNumChildren());
			terrain->removeChildren(0,terrain->getNumChildren());
		}
		osg::ref_ptr<osg::MatrixTransform> storeys;
		osg::ref_ptr<osg::Group> products;
		osg::ref_ptr<osg::Group> spaces;
		osg::ref_ptr<osg::Group> terrain;
	};
	struct BuildingStoreyGroup
	{
		shared_ptr<IfcBuildingStorey> building_storey;
		std::vector<shared_ptr<IfcProduct> > vec_products;
	};
	struct ProductShape
	{
		shared_ptr<IfcProduct> ifc_product;
		osg::ref_ptr<osg::Group> product_group;
		osg::ref_ptr<osg::Group> space_group;
		osg::ref_ptr<osg::Group> terrain_group;
		std::vector<shared_ptr<IfcProduct> > vec_openings;
	};

	void convertIfcModel();
	void convertIfcProject(	shared_ptr<IfcProject> project, ModelGeomTree& result_geom );
	void convertIfcProduct(	shared_ptr<IfcProduct> product, shared_ptr<ProductShape>& product_shape );
	void convertIfcRelAggregates( shared_ptr<IfcRelAggregates> rel_aggregates, ModelGeomTree& result_geom );
	void convertIfcRelContainedInSpatialStructure( shared_ptr<IfcRelContainedInSpatialStructure> relc, ModelGeomTree& result_geom );

	ReaderWriterIFC();
	~ReaderWriterIFC();	
	virtual const char* className() { return "ReaderWriterIFC"; }
	virtual osgDB::ReaderWriter::ReadResult readNode(const std::string& filename, const osgDB::ReaderWriter::Options*);

	ModelGeomTree& getModelGeometryTree() { return m_geom_tree; }
	void setModel( shared_ptr<IfcGearsModel> model );
	shared_ptr<IfcGearsModel> getGearsModel() { return m_ifc_model; }
	shared_ptr<IfcGearsReader> getGearsReader() { return m_step_reader; }
	shared_ptr<IfcStepWriter> getGearsWriter() { return m_step_writer; }
	std::stringstream& getErrors() { return m_err; }

	// heat rays
	void computeHeatRays( osg::Group* grp );
	void computeRaysAtPoint( osg::Group* group, osg::Vec3& rpoint );
	void checkIntersection( osg::Group* group, const osgUtil::LineSegmentIntersector::Intersection& intersection,
		std::vector<shared_ptr<productTreffer> >& treffer_liste );

	static void slotProgressValueWrapper( void* obj_ptr, double value );
	static void slotMessageWrapper( void* obj_ptr, const std::string& str );
	static void slotErrorWrapper( void* obj_ptr, const std::string& str );

protected:
	shared_ptr<IfcGearsModel>		m_ifc_model;
	shared_ptr<IfcGearsReader>		m_step_reader;
	shared_ptr<IfcStepWriter>		m_step_writer;
	std::stringstream				m_err;
	ModelGeomTree					m_geom_tree;
	bool							m_enable_product_color_properties;
	double							m_sum_heat_loss;

	shared_ptr<UnitConverter> m_unit_converter;
	shared_ptr<RepresentationConverter> m_representation_converter;
	osg::ref_ptr<osg::StateSet> m_glass_stateset;
	osg::ref_ptr<osg::StateSet> m_heat_stateset;

	std::map<int,shared_ptr<ProductShape> > m_product_shapes;
	std::map<int,shared_ptr<IfcProduct> > m_processed_products;
	std::map<int, shared_ptr<BuildingStoreyGroup> > m_building_storeys;
	double m_recent_progress;

	// heat rays:
	std::map<shared_ptr<IfcSpace>, osg::ref_ptr<osg::Vec3Array> > m_space_rays;
	std::map<int, std::vector<shared_ptr<ItemData> > > m_product_item_data;
};
